﻿/*
 * PsTFS is a set of PowerShell commands to manage and use Team Foundation Server. PowerShell 
 * effectiveness is combined with the power of TFS API to maximizes TFS capabilities.
 * 
 * Creator : Choulant Noham
 * Mail : choulant@gmail.com
 * Blog : http://choulant.blogspot.com
 * 
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using PsTFS.Objects;
using PsTFS.Objects.Methodes;

namespace PsTFS.Provider
{
    /// <summary>
    /// Implémentation du provider pour Team Foundation Server
    /// </summary>
    [CmdletProvider("TFSProvider", ProviderCapabilities.ShouldProcess)]
    public class TFSProviderOLD : NavigationCmdletProvider
    {
        /// <summary>
        /// Chemin en cour dans le provider TFS
        /// </summary>
        public static string s_root = null;

        /// <summary>
        /// Liste des éléments pouvant être parcourus par le provider
        /// </summary>
        List<StructureBase> listPathValide = null;

        #region Item Methods
        /// <summary>
        /// Permet de modifier la valeur d'un éléments
        /// </summary>
        /// <param name="path">Elément</param>
        /// <param name="values">Valeur</param>
        protected override void SetItem(string path, object values)
        {
            // Write the rows into the table
            WriteWarning("SetItem");
            WriteItemObject(path, path, true);
        }

        /// <summary>
        /// Permet de connaitre l'existance d'un élément
        /// </summary>
        /// <param name="path">Element</param>
        /// <returns>True ou False</returns>
        protected override bool ItemExists(string path)
        {
            s_root = GetPathTFS(path);
            if (String.IsNullOrEmpty(path))
                return false;
            return IsPathValide(path);
        }

        /// <summary>
        /// Permet de connaitre la validité d'un élément
        /// </summary>
        /// <param name="path">Element</param>
        /// <returns>True ou False</returns>
        protected override bool IsValidPath(string path)
        {
            return IsPathValide(path);
        }

        #endregion Item Overloads

        #region Container Methods
        /// <summary>
        /// Permet de parcourir l'ensemble des éléments d'un élément parent
        /// </summary>
        /// <param name="path">Elément parent</param>
        /// <param name="recurse">Parcour le premier niveau ou tous les niveaux</param>
        protected override void GetChildItems(string path, bool recurse)
        {
            //Validation du path
            if (!IsPathValide(path))
                return;
            //Récupération du serveur TFS
            TeamFoundationServer tfs = Context.GetContext().Tfs;
            WorkItemStore witstore = Methode_Service.WIS();
            //Récupération de la commande
            string commande = path.Replace(((TFSDriveInfo)this.PSDriveInfo).Root.Replace("/", "\\") + "\\", "");
            string[] commandes = commande.Split('\\');
            string com1 = commandes[0] != null ? commandes[0] : string.Empty;
            string com2 = commandes.Length > 1 ? commandes[1] : string.Empty;
            string com3 = commandes.Length > 2 ? commandes[2] : string.Empty;
            string com4 = commandes.Length > 3 ? commandes[3] : string.Empty;
            string com5 = commandes.Length > 4 ? commandes[4] : string.Empty;
            string com6 = commandes.Length > 5 ? commandes[5] : string.Empty;
            if (IsProjectValide(com2))
            {
                Context.GetContext().Project = com2;
                com1 = com3;
                com2 = com4;
                com3 = com5;
                com4 = com6;
            }
            #region WORKITEM
            // Vérification si parcour des workitem
            if ("WORKITEM".Equals(com1, StringComparison.OrdinalIgnoreCase) || "WI".Equals(com1, StringComparison.OrdinalIgnoreCase))
            {

                int result = 0;
                if (int.TryParse(com2, out result))
                {
                    WorkItem wi = witstore.GetWorkItem(result);
                    WriteItemObject(wi, path, true);
                }
                else if ("TYPE".Equals(com2, StringComparison.OrdinalIgnoreCase))
                {
                    #region TYPE
                    if (com3 != string.Empty)
                    {
                        #region Recherche les workitems du type demandé
                        string where = Context.GetContext().Project != String.Empty ? " where [System.TeamProject] = '" + Context.GetContext().Project + "'" : String.Empty;
                        where = where != string.Empty ? where + " AND [System.WorkitemType] = '" + com3 + "'" : " where [System.WorkitemType] = '" + com3 + "'";
                        WorkItemCollection wic = witstore.Query("Select [System.ID] from WorkItem " + where);
                        List<StructureWorkitem> list = ConvertItemsToWI(wic, false);
                        WriteItemObject(list, path, true);
                        #endregion Recherche les workitems du type demandé
                    }
                    else
                    {
                        #region Récupére les type de WI
                        List<StructureWorkitemType> listWorkitemType = new List<StructureWorkitemType>();
                        VersionControlServer vcs = Methode_Service.VCS();
                        if (Context.GetContext().Project == string.Empty)
                        {
                            ProjectCollection projects = witstore.Projects;
                            foreach (Project project in projects)
                            {
                                WorkItemTypeCollection witc = project.WorkItemTypes;
                                foreach (WorkItemType wit in witc)
                                {
                                    var t = from u in listWorkitemType
                                            where u.Name == wit.Name
                                            select u as StructureWorkitemType;
                                    if (t.ToList().Count == 0)
                                    {
                                        StructureWorkitemType swt = new StructureWorkitemType() { Name = wit.Name };
                                        listWorkitemType.Add(swt);
                                    }
                                }
                            }
                        }
                        else
                        {
                            WorkItemTypeCollection witc = witstore.Projects[Context.GetContext().Project].WorkItemTypes;
                            foreach (WorkItemType wit in witc)
                            {
                                listWorkitemType.Add(new StructureWorkitemType() { Name = wit.Name });
                            }
                        }
                        WriteItemObject(listWorkitemType, path, true);
                        #endregion Récupére les type de WI
                    }
                    #endregion TYPE
                }
                else if ("State".Equals(com2, StringComparison.OrdinalIgnoreCase))
                {
                    #region State
                    if (com3 != string.Empty)
                    {
                        #region Recherche les workitems du state demandé
                        string where = Context.GetContext().Project != String.Empty ? " where [System.TeamProject] = '" + Context.GetContext().Project + "'" : String.Empty;
                        where = where != string.Empty ? where + " AND [System.State] = '" + com3 + "'" : " where [System.State] = '" + com3 + "'";
                        WorkItemCollection wic = witstore.Query("Select [System.ID] from WorkItem " + where);
                        List<StructureWorkitem> list = ConvertItemsToWI(wic, false);
                        WriteItemObject(list, path, true);
                        #endregion Recherche les workitems du state demandé
                    }
                    else
                    {
                        List<string> listState = new List<string>();
                        VersionControlServer vcs = Methode_Service.VCS();
                        if (Context.GetContext().Project == string.Empty)
                        {
                            ProjectCollection projects = witstore.Projects;
                            foreach (Project project in projects)
                            {
                                WorkItemTypeCollection witc = project.WorkItemTypes;
                                foreach (WorkItemType wit in witc)
                                {
                                    AllowedValuesCollection avc = wit.FieldDefinitions["State"].AllowedValues;
                                    foreach (string s in avc)
                                    {
                                        if (!listState.Contains(s))
                                            listState.Add(s);
                                    }
                                }
                            }
                        }
                        else
                        {
                            WorkItemTypeCollection witc = witstore.Projects[Context.GetContext().Project].WorkItemTypes;
                            foreach (WorkItemType wit in witc)
                            {
                                AllowedValuesCollection avc = wit.FieldDefinitions["State"].AllowedValues;
                                foreach (string s in avc)
                                {
                                    if (!listState.Contains(s))
                                        listState.Add(s);
                                }
                            }
                        }
                        WriteItemObject(listState, path, true);
                    }
                    #endregion State
                }
                else
                {
                    string where = Context.GetContext().Project != String.Empty ? " where [System.TeamProject] = '" + Context.GetContext().Project + "'" : String.Empty;
                    WorkItemCollection wic = witstore.Query("Select [System.ID] from WorkItem " + where);
                    List<StructureWorkitem> list = ConvertItemsToWI(wic, true);
                    WriteItemObject(list, path, true);
                }
            }
            #endregion WORKITEM
            #region SOURCECONTROL
            else if ("SOURCECONTROL".Equals(com1, StringComparison.OrdinalIgnoreCase) || "SC".Equals(com1, StringComparison.OrdinalIgnoreCase))
            {
                List<StructureSC> list = ConvertItemsToList(Methode.GetElementsByPath(GetPathTFS(path), recurse == true ? RecursionType.Full : RecursionType.OneLevel));
                WriteItemObject(list, path, true);
            }
            #endregion SOURCECONTROL
            #region TEAMPROJECT
            else if ("TEAMPROJECT".Equals(com1, StringComparison.OrdinalIgnoreCase) || "TP".Equals(com1, StringComparison.OrdinalIgnoreCase))
            {
                ProjectCollection pc = witstore.Projects;
                List<StructureProject> listStructureProjet = GetElementsByProject(pc);
                WriteItemObject(listStructureProjet, path, true);
            }
            #endregion TEAMPROJECT
            #region BUILD
            else if ("BUILD".Equals(com1, StringComparison.OrdinalIgnoreCase) || "BL".Equals(com1, StringComparison.OrdinalIgnoreCase))
            {
                if ("STATUS".Equals(com2, StringComparison.OrdinalIgnoreCase) || "ST".Equals(com2, StringComparison.OrdinalIgnoreCase))
                {
                    List<string> status = new List<string>();
                    status.Add("Failed");
                    status.Add("InProgress");
                    status.Add("NotStarted");
                    status.Add("PartiallySucceeded");
                    status.Add("Stopped");
                    status.Add("Succeeded");
                    if (status.Contains(com3))
                    {
                        IBuildServer bs = Methode_Service.IBS();
                        IBuildDetail[] listBuild = bs.QueryBuilds(Context.GetContext().Project);
                        List<StructureBuild> listretour = new List<StructureBuild>();
                        List<StructureBuild> list = ConvertItemsToBuild(listBuild);
                        foreach (StructureBuild sb in list)
                        {
                            BuildStatus encour = (BuildStatus)Enum.Parse(typeof(BuildStatus), com3, true);
                            if (sb.Status == encour)
                            {
                                listretour.Add(sb);
                            }
                        }
                        WriteItemObject(listretour, path, true);
                    }
                    else
                    {
                        WriteItemObject(status, path, true);
                    }
                }
                else
                {
                    IBuildServer bs = Methode_Service.IBS();
                    IBuildDetail[] listBuild = bs.QueryBuilds(Context.GetContext().Project);
                    List<StructureBuild> list = ConvertItemsToBuild(listBuild);
                    WriteItemObject(list, path, true);
                }
            }
            #endregion BUILD
            #region MEMBERPROJECT
            else if ("MEMBERPROJECT".Equals(com1, StringComparison.OrdinalIgnoreCase) || "MP".Equals(com1, StringComparison.OrdinalIgnoreCase))
            {
                List<Groups> lg = new List<Groups>();
                lg = Methode.GetMembersProject(Context.GetContext().Project);
                if (!string.IsNullOrEmpty(com2))
                {
                    var lm =  from Groups m in lg
                       where m.DisplayName.Equals(com2, StringComparison.OrdinalIgnoreCase)
                       select m.Members;

                    WriteItemObject(lm, path, true);
                }
                else
                {
                    WriteItemObject(lg, path, true);
                }
            }
            #endregion MEMBERPROJECT
            else
            {
                WriteItemObject(listPathValide, path, true);
            }
        }
        // GetChildItems
        /// <summary>
        /// This override gets child item names, returning the names of all child items.
        /// </summary>
        /// <param name="path">The root path.</param>
        /// <param name="returnContainers">Not used.</param>
        protected override void GetChildNames(string path,
                                              ReturnContainers returnContainers)
        {
            WriteItemObject(path, path, true);
        }
        /// <summary>
        /// Permet de connaitre l'existance d'un élements
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        protected override bool HasChildItems(string path)
        {
            if (path.IndexOf("SourceControl", StringComparison.OrdinalIgnoreCase) != -1 || path.IndexOf("SC", StringComparison.OrdinalIgnoreCase) != -1)
            {
                return (Methode.GetElementsByPath(path, RecursionType.OneLevel).Length > 0);
            }
            return false;
        }
        /// <summary>
        /// Not Implemented
        /// </summary>
        /// <param name="path"></param>
        /// <param name="type"></param>
        /// <param name="newItemValue"></param>
        protected override void NewItem(string path, string type,
                                        object newItemValue)
        {
            //WriteItemObject(path, path, true);
        }
        #endregion Container Methodfs

        /// <summary>
        /// Supprimer un Povider TFS
        /// </summary>
        /// <param name="drive">information</param>
        /// <returns></returns>
        protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
        {
            if (drive == null)
            {
                WriteError(new ErrorRecord(
                           new ArgumentNullException("drive"),
                           "NullDrive",
                           ErrorCategory.InvalidArgument,
                           drive)
                          );
                return null;
            }
            TFSDriveInfo tfsDriveInfo = drive as TFSDriveInfo;
            if (tfsDriveInfo == null)
            {
                return null;
            }
            Context.GetContext().Tfs.Dispose();
            return tfsDriveInfo;
        }
        /// <summary>
        /// Ajout d'un provider TFS
        /// </summary>
        /// <param name="drive">Information</param>
        /// <returns></returns>
        protected override PSDriveInfo NewDrive(PSDriveInfo drive)
        {
            // check if drive object is null
            if (drive == null)
            {
                WriteError(new ErrorRecord(
                           new ArgumentNullException("drive"),
                           "NullDrive",
                           ErrorCategory.InvalidArgument,
                           null)
                          );
                return null;
            }
            if (String.IsNullOrEmpty(drive.Root))
            {
                WriteError(new ErrorRecord(
                           new ArgumentException("drive.Root"),
                           "NoRoot",
                           ErrorCategory.InvalidArgument,
                           drive)
                          );
                return null;
            }
            TFSDriveInfo tfsDriveInfo = new TFSDriveInfo(drive);
            TeamFoundationServer tfs = null;
            if (drive.Root.IndexOf("|") != -1)
            {
                string[] donnees = drive.Root.Split('|');
                if (donnees.Length != 2)
                    return null;
                tfs = new TeamFoundationServer(donnees[0], new UICredentialsProvider());
                Context.GetContext().Project = donnees[1];
            }
            else
            {
                tfs = new TeamFoundationServer(drive.Root, new UICredentialsProvider());
                Context.GetContext().Project = string.Empty;
            }
            tfs.Authenticate();
            Context.GetContext().Tfs = tfs;

            return tfsDriveInfo;
        }

        #region Navigation
        /// <summary>
        /// This overide determine if the path specified is that of a container.
        /// </summary>
        /// <param name="path">The path to check.</param>
        /// <returns>True if the path specifies a container.</returns>
        protected override bool IsItemContainer(string path)
        {
            return true;
        } // End IsItemContainer.
        #endregion Navigation

        private static string GetPathTFS(string path)
        {
            string p = string.Empty;
            string project = Context.GetContext().Project != String.Empty ? Context.GetContext().Project + "/" : String.Empty;
            if (path.LastIndexOf("SOURCECONTROL") != -1)
                p = "$/" + project + path.Substring(path.ToUpper().LastIndexOf("SOURCECONTROL") + 11).Replace("\\", "/");
            else if (path.LastIndexOf("SC") != -1)
                p = "$/" + project + path.Substring(path.ToUpper().LastIndexOf("SC") + 2).Replace("\\", "/");
            else
                p = "$" + project;

            return p;
        }
        private bool IsPathValide(string path)
        {
            if (listPathValide == null)
            {
                listPathValide = new List<StructureBase>();
                StructureBase s1 = new StructureBase() { Alias = "WI", Element = "WORKITEM" };
                StructureBase s2 = new StructureBase() { Alias = "SC", Element = "SOURCECONTROL" };

                listPathValide.Add(s1);
                listPathValide.Add(s2);
                //Récupération de la commande pour extraction du projet en cour
                string commande = path.Replace(((TFSDriveInfo)this.PSDriveInfo).Root.Replace("/", "\\") + "\\", "");
                string[] commandes = commande.Split('\\');
                string com1 = commandes[0] != null ? commandes[0] : string.Empty;
                string com2 = commandes.Length > 1 ? commandes[1] : string.Empty;
                if (IsProjectValide(com2))
                {
                    Context.GetContext().Project = com2;
                }
                else
                {
                    Context.GetContext().Project = String.Empty;
                }
                if (!string.IsNullOrEmpty(Context.GetContext().Project))
                {
                    StructureBase s3 = new StructureBase() { Alias = "MP", Element = "MEMBERSPROJECT" };
                    StructureBase s4 = new StructureBase() { Alias = "DC", Element = "DOCUMENTS" };
                    StructureBase s5 = new StructureBase() { Alias = "BL", Element = "BUILD" };
                    listPathValide.Add(s3);
                    listPathValide.Add(s4);
                    listPathValide.Add(s5);
                }
                else
                {
                    StructureBase s3 = new StructureBase() { Alias = "TP", Element = "TEAMPROJECT" };
                    listPathValide.Add(s3);
                }
            }
            bool retour = false;
            foreach (StructureBase s in listPathValide)
            {
                if (path.IndexOf(s.Alias, StringComparison.OrdinalIgnoreCase) != -1)
                    return true;
                if (path.IndexOf(s.Element, StringComparison.OrdinalIgnoreCase) != -1)
                    return true;
            }
            StructureBase s10 = new StructureBase() { Alias = "", Element = Context.GetContext().Tfs.Name };

            if (path.IndexOf(s10.Alias, StringComparison.OrdinalIgnoreCase) != -1)
                return true;
            if (path.IndexOf(s10.Element, StringComparison.OrdinalIgnoreCase) != -1)
                return true;
            return retour;
        }
        /// <summary>
        /// Permet de convertir un IBuildDetail en structure pour une facilité l'affichage dans PS
        /// </summary>
        /// <param name="listBuild"></param>
        /// <returns></returns>
        private List<StructureBuild> ConvertItemsToBuild(IBuildDetail[] listBuild)
        {
            List<StructureBuild> retour = new List<StructureBuild>();
            Console.WriteLine("STATUS");
            foreach (IBuildDetail bd in listBuild)
            {
                StructureBuild sb = new StructureBuild();
                sb.Agent = bd.BuildAgent.Name;
                sb.Definition = bd.BuildDefinition.Name;
                sb.Finished = bd.BuildFinished;
                sb.FinishTime = bd.FinishTime;
                sb.Number = bd.BuildNumber;
                sb.Server = bd.BuildServer.TeamFoundationServer.Name;
                sb.Status = bd.Status;
                retour.Add(sb);
            }
            return retour;
        }

        /// <summary>
        /// Permet de convertir la liste des éléments du controler de code source dans 
        /// une présentation plus simple à lire dans le prompt
        /// </summary>
        /// <param name="items">Eléments à convertir</param>
        /// <returns>Retour la liste des éléments</returns>
        private List<StructureSC> ConvertItemsToList(Item[] items)
        {
            List<StructureSC> retour = new List<StructureSC>();
            foreach (Item item in items)
            {
                string name = item.ServerItem.Substring(item.ServerItem.LastIndexOf("/") + 1);
                string rep = s_root.Substring(s_root.LastIndexOf("/") + 1);
                if (name.Equals(rep, StringComparison.OrdinalIgnoreCase))
                    name = "..";
                else
                    name = "  " + name;
                if (!name.Trim().Equals(Context.GetContext().Project, StringComparison.OrdinalIgnoreCase))
                    retour.Add(new StructureSC() { Name = name, ItemType = item.ItemType });
            }
            return retour;
        }

        /// <summary>
        /// Vérifi si un projet est valide
        /// </summary>
        /// <param name="com1"></param>
        /// <returns></returns>
        private bool IsProjectValide(string com1)
        {
            ProjectCollection pc = Methode_Service.WIS().Projects;
            foreach (Project p in pc)
                if (p.Name.Equals(com1, StringComparison.OrdinalIgnoreCase))
                    return true;
            return false;
        }

        /// <summary>
        /// Récupère la structure des projets
        /// </summary>
        /// <param name="pc">Liste des projets</param>
        /// <returns></returns>
        private List<StructureProject> GetElementsByProject(ProjectCollection pc)
        {
            List<StructureProject> retour = new List<StructureProject>();
            foreach (Project p in pc)
            {
                retour.Add(new StructureProject() { Name = p.Name });
            }
            return retour;
        }
        #region ConvertItemsToWI
        /// <summary>
        /// Permet de convertir une collection de workitem dans un type d'ojbjet plus simple à gérer dans PS
        /// </summary>
        /// <param name="wic">Collection de workitem</param>
        /// <param name="entete">Permet d'afficher ou non les options de parcour</param>
        /// <returns>Une liste de workitem formatée PsTFS</returns>
        private List<StructureWorkitem> ConvertItemsToWI(WorkItemCollection wic, bool entete)
        {
            List<StructureWorkitem> list = new List<StructureWorkitem>();
            if (entete)
            {
                list.Add(new StructureWorkitem() { Id = 0, Title = "Type", Type = "" });
                list.Add(new StructureWorkitem() { Id = 0, Title = "State", Type = "" });
            }
            foreach (WorkItem w in wic)
            {
                list.Add(new StructureWorkitem() { Id = w.Id, Title = w.Title, Type = w.Type.Name, State = w.State, Reason = w.Reason });
            }
            return list;
        }
        #endregion ConvertItemsToWI

    }

}